﻿using System;
using System.Globalization;
using Skynet.CommonLibrary.ExceptionEx.Inteface;

namespace Skynet.CommonLibrary.ExceptionEx.LogHandler
{
    internal class DefaultLogHandler:ILogHandler
    {
        #region ILogHandler 成员

        public ExceptionEntity SaveLogInfo(IExceptionDataSource datasource, Exception ex, string friendlyInfo, string layerName)
        {
            ExceptionEntity exEntity = new ExceptionEntity
                                           {
                                               FriendlyInfo =
                                                   string.IsNullOrEmpty(friendlyInfo) ? ex.Message : friendlyInfo,
                                               ExMsg = GetExceptionManage(ex),
                                               ExStackTrace = GetExceptionLocation(ex)
                                           };

            if (ex.TargetSite.DeclaringType != null)
                exEntity.ExTarget = ex.TargetSite ==null ?
                                                             ""
                                        :
                                            ex.TargetSite.DeclaringType.FullName + "." +ex.TargetSite.Name;
            exEntity.ExLastTime = DateTime.Now;
            exEntity.LayerName = layerName;
            exEntity.ExId = GetExID(layerName);

            try
            {
                int id = datasource.SaveExceptionInfo(exEntity);
                exEntity.ExId = id;
            }
            catch (Exception exception)
            {
                log4net.LogManager.GetLogger("ErrorLog").Error(
                           string.Format("保存异常到数据库失败。时间:{0}{1}.错误:{2}{1}",
                           DateTime.Now,
                           Environment.NewLine,
                           exception.Message));
            }
            log4net.LogManager.GetLogger("ErrorLog").Error(
             string.Format("错误编号:{0}{1}.错误路径:{2}{1}.错误信息:{3}{1}",
              exEntity.ExId,
             Environment.NewLine,
             exEntity.ExTarget,
             ex.Message));

            return exEntity;
        }

        public ExceptionEntity FindLogInfo(IExceptionDataSource datasource, Exception ex, int exid)
        {
           ExceptionEntity exEntity =  datasource.FindExceptionInfo(exid);
           if (exEntity == null)
           {
               exEntity = new ExceptionEntity
                              {
                                  FriendlyInfo = ex.Message, 
                                  ExMsg = ex.Message,
                                  ExStackTrace = GetExceptionLocation(ex)
                              };
               if (ex.TargetSite.DeclaringType != null)
                   exEntity.ExTarget = ex.TargetSite == null ?
                                                                 ""
                                           :
                                               ex.TargetSite.DeclaringType.FullName + "." + ex.TargetSite.Name;
               exEntity.ExLastTime = DateTime.Now;
               exEntity.LayerName = "Default";
               exEntity.ExId = exid;
               datasource.SaveExceptionInfo(exEntity);
           }
           log4net.LogManager.GetLogger("ErrorLog").Error(
                             string.Format("错误编号:{0}{1}.错误路径:{2}{1}.错误信息:{3}{1}",
                             exEntity.ExId,
                             Environment.NewLine,
                             exEntity.ExTarget,
                             ex.Message));

           return exEntity;
        }
        #endregion

        /// <summary>
        /// 获取最底层的异常信息
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        private string GetExceptionManage(Exception e)
        {
            if (e.InnerException != null)
            {
               return GetExceptionManage(e.InnerException);
            }
            return e.Message;
        }

        /// <summary>
        /// 进行截取过滤以获取错误代码行
        /// </summary>
        /// <param name="e">系统异常</param>
        /// <returns>代码行位置信息</returns>
        private string GetExceptionLocation(Exception e)
        {
            string sLocate = "";

            //获取源异常信息
            string strErr = e.StackTrace;

			if( !string.IsNullOrEmpty(strErr))
			{
				int iLen = strErr.Length;

				//查找第一行，其中行以回车结束
				int iReturnPos = strErr.IndexOf("\r\n", 0, iLen, StringComparison.Ordinal);
				while(iReturnPos > 0 && strErr.Length > 1)
				{
					//判断当前读取的行中有无 line 字样 ， 表示出错的具体代码行
					string sLocateTemp = strErr.Substring(0,iReturnPos);
					if(sLocateTemp.IndexOf("行号", 0, sLocateTemp.Length, StringComparison.Ordinal) > 0)
						sLocate += sLocateTemp + Environment.NewLine ;
                    else if (sLocateTemp.IndexOf("line", 0, sLocateTemp.Length, StringComparison.Ordinal) > 0)
                        sLocate += sLocateTemp + Environment.NewLine;
					//将已判断的行删除，取下一行数据，加4表示/r/n四位
					strErr = strErr.Substring(iReturnPos + 4 , iLen - iReturnPos - 4);
					iLen = strErr.Length ;
					iReturnPos = strErr.IndexOf("\r\n", 0, iLen, StringComparison.Ordinal);
				}

				if(strErr.IndexOf("行号", 0, strErr.Length, StringComparison.Ordinal) > 0)
					sLocate += strErr + Environment.NewLine ;
                else if (strErr.IndexOf("line", 0, strErr.Length, StringComparison.Ordinal) > 0)
                    sLocate += strErr + Environment.NewLine;
			}

            //if (strErr != string.Empty && strErr != null)
            //{
            //    if (strErr.IndexOf("\r\n") == -1)
            //    {
            //        sLocate = strErr;
            //    }
            //    else
            //    {
            //        if (strErr.IndexOf("\r\n") > 0)
            //        {
            //            sLocate = strErr.Substring(strErr.LastIndexOf("\r\n"));
            //        }
            //    }
            //}
            return sLocate.Trim();
        }

        /// <summary>
        /// 通过取Hash值最后2位作为异常ID的头 
        /// </summary>
        /// <param name="layername"></param>
        /// <returns>返回5位有效数字 不足后面补0</returns>
        private int GetExID(string layername)
        {
            //通过层的哈希值最后2位作为 异常编号的头
            string hashCode = layername.GetHashCode().ToString(CultureInfo.InvariantCulture);
            string codeID = hashCode.Remove(0, hashCode.Length - 2);
            return  int.Parse(codeID.PadRight(5, '0'));
        }
    }
}
